  //
// Created by benny on 2022/3/10.
//

#ifndef CPPCOROUTINES__IO_H_
#define CPPCOROUTINES__IO_H_

#include <iostream>
#include <sstream>
#include <chrono>
#include <ctime>
#include <iomanip>
#include <thread>


inline char separator() {
#ifdef _WIN32
    return '\\';
#else
    return '/';
#endif
}

const char *file_name(const char *path) {
    const char *file = path;
    while (*path) {
        if (*path++ == separator()) {
            file = path;
        }
    }
    return file;
}

std::stringstream &PrintTime(std::stringstream &ss) {
    using namespace std;
    using namespace std::chrono;

    auto now = system_clock::now();
    auto in_time_t = system_clock::to_time_t(now);

    // get number of milliseconds for the current second
    // (remainder after division into seconds)
    auto ms = duration_cast<milliseconds>(now.time_since_epoch()) % 1000;

    ss << std::put_time(std::localtime(&in_time_t), "%R")
       << '.' << std::setfill('0') << std::setw(3) << ms.count();
    return ss;
}

std::stringstream &PrintThread(std::stringstream &ss) {
    using namespace std;
    ss << " [Thread-" << setw(5) << this_thread::get_id() << "] ";
    return ss;
}

template<typename ... U>
void Println(std::stringstream &ss, U... u) {
  int i = 0;
  auto printer = [&ss, &i]<typename Arg>(Arg arg) {
    if (sizeof...(U) == ++i) ss << arg << std::endl;
    else ss << arg << " ";
  };
  (printer(u), ...);

  std::cout << ss.str();
  std::cout.flush();
}

#define debug(...) \
do {               \
std::stringstream ss;\
PrintTime(ss);       \
PrintThread(ss);   \
char buf[100];                   \
size_t len = snprintf(buf, 100, "(%s:%d) %s: ", file_name(__FILE__), __LINE__, __func__); \
std::string s(buf, buf + len - 1);                                                       \
Println(ss, s, __VA_ARGS__);     \
} while(0)

#endif //CPPCOROUTINES__IO_H_
